/**
 * ScoreHandler.java
 * 
 * The ScoreHandler class is an abstract handler in the Chain of Responsibility
 * pattern. It defines abstract methods for calculating the final score of each
 * ball rolled. (There are two balls rolled for normal frames and three balls
 * that can be rolled for the last frame.)
 * 
 * Once the score for the current ball is known, setOriginalScore should be
 * called. Once the next score handler is known, setNextHandler is called. To
 * get the most accurate calculation of the score, call getCalculatedScore.
 * To get the score of all the balls in this frame, call getFrameScore.
 * 
 * @author Robert Yates
 * @author Ryan Walters
 */

public abstract class ScoreHandler {

	/**
	 * The handler representing the score of the next ball thrown by the same
	 * player.
	 */
	protected ScoreHandler nextHandler;

	/**
	 * The score representing the number of pins knocked down by this ball.
	 */
	protected int originalScore;

	/**
	 * Add this handler to the end of the chain of handlers.
	 * 
	 * @param handler		The new last handler
	 */
	public void setLastHandler(ScoreHandler handler) {
		if (nextHandler == null) {
			nextHandler = handler;
		} else if (nextHandler != handler){
			nextHandler.setLastHandler(handler);
		}
	}

	/**
	 * This method is called to set the score for the current ball.
	 * 
	 * @param score		The original score of this ball.
	 */
	public void setOriginalScore(int score) {
		originalScore = score;
	}

	/**
	 * This method is called to get the score originally set for this ball.
	 * 
	 * @return 		The original score of this ball.
	 */
	public int getOriginalScore() {
		return originalScore;
	}

	/**
	 * Returns the most accurate calculation of the score.
	 * 
	 * @return 		The original score plus any subsequent scores if they are 
	 * 				used to calculate this total score.
	 */
	public abstract int getCalculatedScore();

	/**
	 * Gets the score of the entire frame. If this is not the last frame, then
	 * there are two score handlers representing two balls in this frame. If
	 * this is the last frame, then there are three score handlers representing
	 * three balls in this frame.
	 * 
	 * @param isLastFrame
	 *            True, if this is the final frame with three balls. 
	 *            False, if this is a normal frame with two balls.
	 * @return 	  The total score of this frame.
	 */
	public int getFrameScore(boolean isLastFrame) {
		int frameScore = 0;
		if (!isLastFrame) {

			// Get the calculated score for the current ball and add it to
			// the frame's total.
			frameScore += getCalculatedScore();
			if (nextHandler != null && frameScore <= 10) {
				
				// If the next handler exists and a strike wasn't bowled for
				// the first ball, get the calculated score for the next ball
				// and add it to the frame's total.
				frameScore += nextHandler.getCalculatedScore();
			}
		} else {
			// Add all the original scores together for the last frame.
			frameScore += getOriginalScore();
			if (nextHandler != null) {
				frameScore += nextHandler.getOriginalScore();
				if (nextHandler.nextHandler != null) {
					frameScore += nextHandler.nextHandler.getOriginalScore();
				}
			}
		}
		return frameScore;
	}
}
